//
//  WatchCommandTool.m
//  Lightthings
//
//  Created by Hero on 2024/9/3.
/*
 "深圳添翼精密电子有限公司APP协议格式：没有特殊说明的数据都是以大端序为主
   标识符  + 帧数 + 总帧数 + 功能标记 + 校验和 + 数据包长度 + 功能码 + 数据长度 + 数据
    APP或者设备请求读取数据格式：标识符  + 帧数 + 总帧数 + 功能标记 + 校验和 + 数据包长度 + 功能码 + 0x0000"
*/

#import "WatchCommandTool.h"
#import <AVKit/AVKit.h>
#import "GPSDataManager.h"
@interface WatchCommandTool ()
/* <#note#> */
@property (nonatomic, assign) SystemSoundID soundId;
@property (nonatomic, assign) BOOL stopSoundAndVibrate;
@end

@implementation WatchCommandTool
SingletonM;
// MARK:   🔥🔥🔥🔥🔥🔥🔥 基础算法 🔥🔥🔥🔥🔥🔥🔥
- (void)writeStormCommand:(DeviceCommandEnum)type ToPeripheral:(CBPeripheral *)peripheral Value:(NSArray *)value reBack:(void (^)(NSString * _Nonnull))bacdata {
    Byte HeadData[2] = {0x54,0x59};
    Byte frameNumber[1] = {0x01}; //  帧数
    Byte allFrameNumber[1] = {0x01}; //  总帧数
    Byte sign[1] = {0x00}; // 功能标记
    Byte checkSum[2] = {0x00, 0x00}; // 校验和  校验和 = 功能码 + 数据长度 + 数据
    Byte dataPackLength[2] = {0x00, 0x00}; // 数据包长度 = 功能码字节数 + 数据长度字节数 + 数据字节数
    Byte fountionCode[2]  = {0x00, 0x00};; // 功能码
    Byte dataLength[2] = {0x00, 0x00};//数据长度（2byte） 数据的字节数

    int sum = 0;
    for (NSNumber * a  in value) {
        sum+=a.intValue;
    }
    
    unsigned long sumInt = [[self getFoutionCode:type].firstObject intValue]+ [[self getFoutionCode:type].lastObject intValue] + value.count + sum;
    unsigned char byte1 = (sumInt & 0xff00)>>8; //高8位
    unsigned char byte2 = (sumInt & 0xff);//低8位
    checkSum[0] = byte1;
    checkSum[1] = byte2;
    
    unsigned long packInt = 2 + 2 + value.count;
    dataPackLength[0] = (packInt & 0xff00)>>8; //高8位
    dataPackLength[1] = (packInt & 0xff);//低8位
    
    fountionCode[0] = [[self getFoutionCode:type].firstObject intValue] & 0xff;
    fountionCode[1] = [[self getFoutionCode:type].lastObject intValue] & 0xff;
     
    if (value.count > 0) {
        dataLength[0] = (value.count & 0xff00)>>8; //高8位
        dataLength[1] = (value.count & 0xff);//低8位
    }
    //标识符  + 帧数 + 总帧数 + 功能标记 + 校验和 + 数据包长度 + 功能码 + 数据长度 + 数据
    NSMutableData * allCommand = [[NSMutableData alloc] initWithBytes:HeadData length:sizeof(HeadData)];
    [allCommand appendBytes:frameNumber length:sizeof(frameNumber)];
    [allCommand appendBytes:allFrameNumber length:sizeof(allFrameNumber)];
    [allCommand appendBytes:sign length:sizeof(sign)];
    [allCommand appendBytes:checkSum length:sizeof(checkSum)];
    [allCommand appendBytes:dataPackLength length:sizeof(dataPackLength)];
    [allCommand appendBytes:fountionCode length:sizeof(fountionCode)];
    [allCommand appendBytes:dataLength length:sizeof(dataLength)];
    
    for (int i = 0; i < value.count; i ++) {
        Byte b = [value[i] intValue] & 0xff;
        Byte byte[] = {b};
        [allCommand appendBytes:byte length:sizeof(byte)];
    }
    
    NSLog(@"allCommand  = %@", allCommand);
    
    [[FRQBluetoothManager shareManager] sendCommandData:allCommand ToPeripheral:peripheral completion:^(NSString * _Nonnull resultString) {
        
        DDLogDebug(@"返回数据：%@， 指令：%@",resultString, [resultString substringWithRange:NSMakeRange(18, 4)]);
        
        
        NSString * a = [resultString substringWithRange:NSMakeRange(18, 2)];
        NSString * b = [resultString substringWithRange:NSMakeRange(20, 2)];
        
        if ([[resultString substringWithRange:NSMakeRange(18, 4)] isEqualToString:@"0216"]) {
            if ([resultString hasSuffix:@"00"]) {
                self.stopSoundAndVibrate = NO;
                [self playAlarmSound];
            }else {
                self.stopSoundAndVibrate = YES;
                [self stopSystemSound];
            }
            bacdata(nil);
        }else if ([[resultString substringWithRange:NSMakeRange(18, 4)] isEqualToString:@"030a"]) {
            if (resultString.length > 26) {
                [GPSDataManager.sharedInstance addNewGPSData:[resultString substringFromIndex:26]];
            }
            bacdata(resultString);
        }else if (strtoll([[NSString stringWithFormat:@"0x%@",a] UTF8String], 0, 16) == [[self getFoutionCode:type].firstObject intValue] && strtoll([[NSString stringWithFormat:@"0x%@",b] UTF8String], 0, 16) == [[self getFoutionCode:type].lastObject intValue]) {
            bacdata(resultString);
        }else {
            bacdata(nil);
        }
        
    }];
}

- (void)readStormCommand:(DeviceCommandEnum)type ToPeripheral:(CBPeripheral *)peripheral reBack:(void (^)(NSString * _Nonnull))bacdata {
    
    [self writeStormCommand:type ToPeripheral:(CBPeripheral *)peripheral Value:@[] reBack:bacdata];
    
}

- (NSArray *)getFoutionCode:(DeviceCommandEnum)type {
    switch (type) {
        case Command_Handshake:
            return @[@0, @1];
            break;
        case Command_ChipInfo:
            return @[@0, @2];
            break;
        case Command_Bind:
            return @[@1, @1];
            break;
        case Command_unbind:
            return @[@1, @4];
            break;
        case Command_FounctionList:
            return @[@1, @2];
            break;
        case Command_DeviceInfo:
            return @[@0, @4];
            break;
        case Command_Alarm:
            return @[@2, @9];
            break;
        case Command_Sedentary:
            return @[@2, @3];
            break;
        case Command_StepGoal:
            return @[@2, @1];
            break;
        case Command_Notification:
            return @[@2, @0x0A];
            break;
        case Command_RaiseHand:
            return @[@2, @6];
            break;
        case Command_DialSwitch:
            return @[];
            break;
        case Command_ScreenTime:
            return @[@2, @2];
            break;
        case Command_OTA_Upgrade:
            return @[];
            break;  
        case Command_OTA_Version:
            return @[@0, @3];
            break;
        case Command_HeartRateReminders:
            return @[@2, @0x0b];
            break; 
        case Command_CurrentData:
            return @[@3, @1];
            break;
        case Command_HeartRateHistory:
            return @[@3, @5];
            break;
        case Command_BloodOxygenHistory:
            return @[@3, @7];
            break;
        case Command_SleepHistory:
            return @[@3, @8];
            break;
        case Command_SportRecord:
            return @[@3, @2];
            break;
        case Command_SportControl:
            return @[@3, @3];
            break; 
        case Command_NowWeather:
            return @[@4, @3];
            break;
        case Command_DelayWeather:
            return @[@4, @4];
            break; 
        case Command_UpdateDate:
            return @[@4, @5];
            break;
        case Command_VibrationSet:
            return @[@2, @5];
            break;   
        case Command_12_24_Set:
            return @[@2, @7];
            break;
        case Command_LengthSet:
            return @[@2, @0x11];
            break;
        case Command_TemperatureSet:
            return @[@2, @0x12];
            break;
        case Command_Water:
            return @[@2, @0x0c];
            break;
        case Command_Medicine:
            return @[@2, @0x0d];
            break;
        case Command_PhysiologicalPeriod:
            return @[@2, @0x0e];
            break;
        case Command_BodyTemperature:
            return @[@2, @0x0f];
            break;  
        case Command_Antilost:
            return @[@2, @0x10];
            break;
        case Command_DoNotDisturb:
            return @[@2, @04];
            break;
        case Command_FindPhone:
            return @[@2, @0x16];
            break;
        case Command_FindWatch:
            return @[@2, @0x17];
            break;
        case Command_UserInfo:
            return @[@2, @0x19];
            break;
        case Command_LanguageSet:
            return @[@2, @0x8];
            break;  
        case Command_BloodPressureHistory:
            return @[@3, @06];
            break;
        case Command_SOS:
            return @[@2, @0x13];
            break;   
        case Command_GPSData:
            return @[@3, @0x0A];
            break;
        case Command_SetUserInfo:
            return @[@2, @0x19];
            break;
        default:
            break;
    }
    return @[@0,@0];
}

// MARK:   🔥🔥🔥🔥🔥🔥🔥 各种指令方法  🔥🔥🔥🔥🔥🔥🔥
- (void)readRealTimeDataFromPeripheral:(CBPeripheral *)peripheral  Block:(void (^)(BOOL, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long))backBlock {
    [[WatchCommandTool sharedInstance] readStormCommand:Command_CurrentData ToPeripheral:peripheral reBack:^(NSString * _Nonnull backData) {
        if (backData) {
            NSString * valueStr = [backData substringWithRange:NSMakeRange(26, 8)];
            unsigned long value = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"当前步数：%lu",value);
            [WatchCommandTool sharedInstance].stepNum = value;
            
            valueStr = [backData substringWithRange:NSMakeRange(34, 8)];
            value = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"当前卡路里：%lu",value);
            [WatchCommandTool sharedInstance].calories = value;
            
            valueStr = [backData substringWithRange:NSMakeRange(42, 8)];
            value = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"当前距离：%lu",value);
            [WatchCommandTool sharedInstance].distance = value;
            
            valueStr = [backData substringWithRange:NSMakeRange(50, 2)];
            value = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"当前心率：%lu",value);
            [WatchCommandTool sharedInstance].heartRate = value;
            
            valueStr = [backData substringWithRange:NSMakeRange(52, 2)];
            value = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"当前电量：%lu",value);
            [WatchCommandTool sharedInstance].electric = value;
            
            
            !backBlock? :backBlock(YES,self.stepNum, self.calories, self.distance, self.heartRate, self.electric);
            
        }else {
            !backBlock? :backBlock(NO,0,0,0,0,0);
        }
    }];
}

- (void)readStepTargetData:(void (^)(BOOL, unsigned long))backBlock ToPeripheral:(CBPeripheral *)peripheral{
    [[WatchCommandTool sharedInstance] readStormCommand:Command_StepGoal ToPeripheral:peripheral reBack:^(NSString * _Nonnull backData) {
        if (backData) {
            NSString * valueStr = [backData substringWithRange:NSMakeRange(26, 8)];
            unsigned long value = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"当前数值：%lu",value);
            !backBlock? :backBlock(YES,value);
        }else {
            !backBlock? :backBlock(NO,0);
        }
    }];
}

- (void)readSleepData:(void (^)(BOOL, unsigned long, unsigned long, unsigned long))backBlock  ToPeripheral:(CBPeripheral *)peripheral{
    [[WatchCommandTool sharedInstance] readStormCommand:Command_SleepHistory ToPeripheral:peripheral reBack:^(NSString * _Nonnull backData) {
        if (backData.length > 26) {
            NSString * valueStr = [backData substringWithRange:NSMakeRange(26, 4)];
            
            unsigned long value = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"浅睡眠时间（分）：%lu",value);

            valueStr = [backData substringWithRange:NSMakeRange(30, 4)];
            unsigned long  value2 = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"深睡眠时间（分）%lu",value2);

            valueStr = [backData substringWithRange:NSMakeRange(38, 8)];
            unsigned long  value3 = strtoll([[NSString stringWithFormat:@"0x%@",valueStr] UTF8String], 0, 16);
            NSLog(@"时间：%@",valueStr);
            !backBlock? :backBlock(NO,value2, value, value3);
        }else {
            !backBlock? :backBlock(NO,0, 0, 0);
        }
        
    }];
}

///  读取血压数据
/// - Parameter backBlock: 是否成功，<日期  收缩压  舒张压>
- (void)readBloodPressureData:(void(^)(BOOL success, NSArray  *list))backBlock ToPeripheral:(CBPeripheral *)peripheral; {
    [WatchCommandTool.sharedInstance writeStormCommand:Command_BloodPressureHistory ToPeripheral:peripheral Value:nil reBack:^(NSString * _Nonnull backData) {
        if (backData.length > 26) {
            NSString * valueStr = [backData substringFromIndex:26];
            NSMutableArray * arr = [NSMutableArray array];
            for (int i = 0 ; i < valueStr.length / 12; i ++) {
                NSString * itemStr = [valueStr substringWithRange:NSMakeRange(i * 12, 12)];
                NSString * dateD = [itemStr substringToIndex:8];
                NSString * shousuo = [itemStr substringWithRange:NSMakeRange(8, 2)];
                NSString * shuzhang = [itemStr substringWithRange:NSMakeRange(10, 2)];
                unsigned long dateValue = strtoll([[NSString stringWithFormat:@"0x%@",dateD] UTF8String], 0, 16);
                NSString * dateStr = [SWTool timeWithYearMonthDayCountDown:[NSString stringWithFormat:@"%lu",dateValue] Format:@"yyyy-MM-dd HH:mm:ss"];
                unsigned long shousuoValue = strtoll([[NSString stringWithFormat:@"0x%@",shousuo] UTF8String], 0, 16);
                unsigned long shuzhangValue = strtoll([[NSString stringWithFormat:@"0x%@",shuzhang] UTF8String], 0, 16);
                [arr addObject:@{
                    @"d":dateStr, @"s":[NSString stringWithFormat:@"%ld",shousuoValue],@"r":[NSString stringWithFormat:@"%ld", shuzhangValue]
                }];
            }
            !backBlock? :backBlock(YES,arr);
        }else {
            !backBlock? :backBlock(NO,nil);
        }
    }];
}

- (void)readBloodOxygenData:(void (^)(BOOL, NSArray * _Nonnull))backBlock ToPeripheral:(CBPeripheral *)peripheral{
    [[WatchCommandTool sharedInstance] readStormCommand:Command_BloodOxygenHistory ToPeripheral:peripheral reBack:^(NSString * _Nonnull backData) {
        if (backData.length > 26) {
            NSString * valueStr = [backData substringFromIndex:26];
            NSMutableArray * mutArr = [NSMutableArray array];
            for (int i = 0 ; i < valueStr.length / 10; i ++) {
                NSString * itemStr = [valueStr substringWithRange:NSMakeRange(i * 10, 10)];
                NSString * dateD = [itemStr substringToIndex:8];
                NSString * rateD = [itemStr substringFromIndex:8];
                unsigned long dateValue = strtoll([[NSString stringWithFormat:@"0x%@",dateD] UTF8String], 0, 16);
                NSString * dateStr = [SWTool timeWithYearMonthDayCountDown:[NSString stringWithFormat:@"%lu",dateValue] Format:@"yyyy-MM-dd HH:mm:ss"];
                unsigned long rateValue = strtoll([[NSString stringWithFormat:@"0x%@",rateD] UTF8String], 0, 16);
                [mutArr addObject:itemStr];
            }
            backBlock(YES,mutArr);
        }else {
            backBlock(NO, nil);
        }
    }];
}

- (void)readSportData:(void(^)(BOOL success, NSArray<NSArray *> *allData))backBlock ToPeripheral:(CBPeripheral *)peripheral{
    //    02 66e56ff2 0000002f 00000000 00000000 00000000 53 ffffffff
    //    02 66e570d1 00000014 0000000d 000000c8 00000006 60 ffffffff
    //    14 66e587a1 00000019 00000000 00000000 00000000 50 ffffffff
    //    01 675a52c8 00000a93 00002f03 0008ef97 000016e7 7c ffff ffff
    [[WatchCommandTool sharedInstance] readStormCommand:Command_SportRecord ToPeripheral:peripheral reBack:^(NSString * _Nonnull backData) {
        if (backData.length > 26) {
            NSString * valueStr = [backData substringFromIndex:26];
            NSMutableArray * mutArr = [NSMutableArray array];
            for (int i = 0 ; i < valueStr.length / 52; i ++) {
                NSString * itemStr = [valueStr substringWithRange:NSMakeRange(i * 52, 52)];
                NSString * typeStr = [itemStr substringWithRange:NSMakeRange(0, 2)];
                NSString * startTimeStr = [itemStr substringWithRange:NSMakeRange(2, 8)];
                NSString * sportTimeStr = [itemStr substringWithRange:NSMakeRange(10, 8)];
                NSString * stepNumStr = [itemStr substringWithRange:NSMakeRange(18, 8)];
                NSString * caloStr = [itemStr substringWithRange:NSMakeRange(26, 8)];
                NSString * distanceStr = [itemStr substringWithRange:NSMakeRange(34, 8)];
                NSString * rateStr = [itemStr substringWithRange:NSMakeRange(42, 2)];
                NSString * peisuStr = [itemStr substringWithRange:NSMakeRange(44, 4)];
                NSString * bupinStr = [itemStr substringWithRange:NSMakeRange(48, 4)];
                
                DDLogDebug(@"读取到运动数据：%@",itemStr);

                [mutArr addObject:@[typeStr, startTimeStr,sportTimeStr,stepNumStr,caloStr,distanceStr, rateStr, peisuStr, bupinStr]];
            }
            backBlock(YES,mutArr);
        }else {
            backBlock(NO, nil);
        }
    }];
}

- (void)writeAlermInfo:(AlermModel *)model CallBack:(void (^)(BOOL))backBlock ToPeripheral:(CBPeripheral *)peripheral{
    long a = strtol([model.repeat UTF8String], NULL, 2);
    NSArray * arr = @[@0x01,@(model.alermID),@(model.isOpen),@(a),@(model.alert_H),@(model.alert_M)];
    [self writeStormCommand:Command_Alarm ToPeripheral:peripheral Value:arr reBack:^(NSString * _Nonnull backData) {
        if (backData.length) {
            backBlock(YES);
        }
    }];
}

- (void)updateDateAndTimeCallBack:(void (^)(BOOL))backBlock  ToPeripheral:(CBPeripheral *)peripheral{
    
    NSMutableArray * dataArray = [NSMutableArray array];
    /// 时间戳
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
     [formatter setDateStyle:NSDateFormatterMediumStyle];
     [formatter setTimeStyle:NSDateFormatterShortStyle];
     [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
     //设置时区,这个对于时间的处理有时很重要
     NSTimeZone* timeZone = [NSTimeZone systemTimeZone];
     [formatter setTimeZone:timeZone];
     NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
    long value = (long)[datenow timeIntervalSince1970];
    unsigned char byte1 = (value & 0xff000000)>>24;
    unsigned char byte2 = (value & 0xff0000)>>16;
    unsigned char byte3 = (value & 0xff00)>>8;
    unsigned char byte4 = (value & 0xff);
    
    [dataArray addObject:@(byte1)];
    [dataArray addObject:@(byte2)];
    [dataArray addObject:@(byte3)];
    [dataArray addObject:@(byte4)];
    
    
    NSCalendar *calendar=[[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    [calendar setTimeZone:timeZone];
    NSCalendarUnit calendarUnit=NSCalendarUnitWeekday;
    NSDateComponents *components=[calendar components:calendarUnit fromDate:datenow];
    long week = components.weekday - 1;//  星期日 = 1
    unsigned char byte5 = (week & 0xff);
    [dataArray addObject:@(byte5)];

    long secondFromGMT = timeZone.secondsFromGMT;
    long a = secondFromGMT / (60 * 15);
    [[NSUserDefaults standardUserDefaults] setValue:@(secondFromGMT) forKey:@"secondFromGMT"];
    if (secondFromGMT > 0) {
        unsigned char byte6 = (a & 0x7f) ;
        [dataArray addObject:@(byte6)];
    }else {
        unsigned char byte6 = (a | 0x80) ;
        [dataArray addObject:@(byte6)];
    }
    
    [[WatchCommandTool sharedInstance] writeStormCommand:Command_UpdateDate ToPeripheral:peripheral Value:dataArray reBack:^(NSString * _Nonnull backData) {
        if (backData.length > 26 && [backData hasSuffix:@"00"]) {
            backBlock(YES);
        }else {
            backBlock(NO);
        }
    }];
    
}

- (void)setAudioPlaySession {
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    if([NSThread mainThread]){
        [audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
        [audioSession setActive:YES error:nil];
    }else{
        dispatch_async(dispatch_get_main_queue(), ^{
            [audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
            [audioSession setActive:YES error:nil];
        });
    }
}
- (void)playAlarmSound {
    [self setAudioPlaySession];
//    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:type];
//       //组装并播放音效
//       SystemSoundID soundID;
//       NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
//       AudioServicesCreateSystemSoundID((__bridge CFURLRef)filePath, &soundID);
    self.soundId = 1321;// 生成的soundID要用全局变量保存，循环播放要用到。
    [self playIOS9LaterConsecutivelyAlarmSoundId:self.soundId];
}
// iOS9以后持续播放声音
- (void)playIOS9LaterConsecutivelyAlarmSoundId:(SystemSoundID)soundID{
    NSLog(@"开始播放 soundID = %d",soundID);
    if (soundID == 0) {
        return;
    }
    AudioServicesPlaySystemSoundWithCompletion(soundID, ^{
        if (!self.stopSoundAndVibrate) {// 播放结束判断是否已经点击停止
// 当播放一便结束之后再次调用该方法
            [self playIOS9LaterConsecutivelyAlarmSoundId:self.soundId];
        }else {
            [self stopSystemSound];
        }
    });
}

/********************ios9 之前调用的方法********************/
- (void)playIOS9BeforeConsecutivelyAlarmSound{
    // soundCompletionCallback 播放完成的回调
    AudioServicesAddSystemSoundCompletion(self.soundId, NULL, NULL,soundCompletionCallback , NULL);
    AudioServicesPlaySystemSound(self.soundId);

}

// iOS9以前持续播放声音
static void soundCompletionCallback (SystemSoundID soundID,void* sample) {
    AudioServicesPlaySystemSound(soundID);//循环播放
}


// 停止报警声跟振动
- (void)stopSystemSound {
    self.stopSoundAndVibrate = YES;
    AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
    AudioServicesRemoveSystemSoundCompletion(self.soundId);
    AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate);
    AudioServicesDisposeSystemSoundID(self.soundId);
    self.soundId = 0;

}

@end
